import { getMemberWithDefault } from "./prop-path";

/**
 * 分组树
 */
export type GroupTree<Member,Group extends PropertyKey = string> = {members?:Member[]} & {  [C in Group]?:GroupTree<Member,Group>};

/**
 * 获取分组路径
 */
export type GetGroupPath<Member,Group extends PropertyKey = string> = (member:Member,index:number,array:Member[])=>Group[];


/**
 * 根据 getGroupPath 提示的多层级分组信息，将 members 整理成 树状的分组层级结构
 * @param members 
 * @param getGroupPath 
 * @returns 
 */
export function groupTreeBy<Member,Group extends PropertyKey = string>(members:Member[],getGroupPath:GetGroupPath<Member,Group>){
    const groups = { members: [] } as unknown as GroupTree<Member,Group>;
    const length = members.length;
    for (let i =0;i<length;i++){
        const item = members[i];
        const paths = getGroupPath(item,i,members);
        const node:GroupTree<Member,Group> = getMemberWithDefault(groups,paths,()=>({members:[]}));
        const mems = node.members ?? (node.members = []);
        mems.push(item);
    }
    return groups;
}


/**
 * 获取组树某个节点的子组名字
 * @param node 
 * @returns 
 */
export function getSubGroupNames<Group extends PropertyKey = string>(node:GroupTree<any,Group>):Group[]{
    const groups = Object.keys(node) as Group[];
    return groups.filter((group)=>isGroupTree(node[group]));
}


/**
 * 获取某个节点的所有直接子组节点
 * @param node 
 * @returns 
 */
export function getSubGroupNodes<Member,Group extends PropertyKey = string>(node:GroupTree<Member,Group>):GroupTree<Member,Group>[]{
    const sNodes = Object.values(node) as GroupTree<Member,Group>[];
    return sNodes.filter((sNode)=>isGroupTree(sNode));
}

/**
 * 获取某个节点的所有直接子组名字 和 对应的节点
 * @param node 
 * @returns 
 */
export function getSubGroupEntries<Member,Group extends PropertyKey = string>(node:GroupTree<any,Group>):[Group,GroupTree<Member,Group>][]{
    const sNodes = Object.entries(node) as unknown as [Group,GroupTree<Member,Group>][];
    return sNodes.filter(([group,sNode])=>isGroupTree(sNode));
}


/**
 * 判断 目标是否不是 GroupTree
 * @param target 
 * @returns 
 */
export function isGroupTree(target?:any){
    return target && !Array.isArray(target) && typeof target === "object";
}


/**
 * 判断组节点是否包含子组
 * @param node 
 * @returns 
 */
export function hasSubGroups(node:GroupTree<any,any>):boolean{
    const sNodes = Object.values(node);
    return sNodes.some((sNode)=>isGroupTree(sNode));
}








/**
 * 扁平化组树
 * @remarks
 * @param tree 
 * @returns 返回启平后的 所有成员 和 所有节点
 *      + members - 包含树中所有节点的成员
 *      + nodes - 树的所有节点
 */
export function flatGroupTree<Member>(tree:GroupTree<Member,PropertyKey>){
    
    const members:Member[] = [];
    let nodes:GroupTree<Member,PropertyKey>[] = [tree];
    for (let i=0;i<nodes.length;i++){
        const node = nodes[i];
        const {members:mems,...groups} = node;
        if (mems){
            members.push(...mems);
        }
        // @ts-ignore
        nodes.push(...Object.values(groups));
    }

    return {members,nodes};
}